package com.flow.framework.core.system.initialization;

import com.flow.framework.common.type.TypeReference;
import com.flow.framework.common.util.verify.VerifyUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;

import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * spring上下文的工具类
 *
 * @author luoguopiao
 * @version 0.0.1
 * @date 2022/1/23
 */
@Slf4j
public class ApplicationContextHelper {
    private static ApplicationContext applicationContext;

    /**
     * 设置方法的访问权限为默认，防止其他地方对该方法进行访问
     *
     * @param context spring上下文
     */
    static void setApplicationContext(ApplicationContext context) {
        applicationContext = context;
    }

    /**
     * 根据bean的类型获取bean集合
     *
     * @param clazz bean的父类或者接口
     * @return bean对应的集合
     */
    public static <T> Collection<T> getBeans(Class<T> clazz) {
        try {
            Map<String, T> beansMap = applicationContext.getBeansOfType(clazz);
            if (VerifyUtil.isEmpty(beansMap)) {
                return Collections.emptySet();
            }
            return beansMap.values();
        } catch (Exception e) {
            log.debug("get bean error.", e);
        }
        return Collections.emptySet();
    }

    /**
     * 根据bean的类型获取bean名称和bean的map
     *
     * @param clazz bean的父类或者接口
     * @param <T>   T
     * @return bean名称和bean的map
     */
    public static <T> Map<String, T> getBeanNameAndBeanMap(Class<T> clazz) {
        try {
            Map<String, T> beansMap = applicationContext.getBeansOfType(clazz);
            if (VerifyUtil.isEmpty(beansMap)) {
                return Collections.emptyMap();
            }
            return beansMap;
        } catch (Exception e) {
            log.debug("get bean error.", e);
        }
        return Collections.emptyMap();
    }

    /**
     * 根据bean名称和类型获取bean
     *
     * @param beanName bean的名称
     * @param type     bean的类型
     * @return bean
     */
    @Nullable
    public static <T> T getBeanByName(String beanName, Class<T> type) {
        try {
            return applicationContext.getBean(beanName, type);
        } catch (Exception e) {
            log.debug("get bean error.", e);
        }
        return null;
    }

    /**
     * 根据注解的类型获取bean集合
     *
     * @param annotationClazz 注解class
     * @return bean对应的集合
     */
    public static Collection<Object> getBeansWithAnnotation(Class<? extends Annotation> annotationClazz) {
        Map<String, Object> beansMap = applicationContext.getBeansWithAnnotation(annotationClazz);
        return beansMap.values();
    }

    /**
     * 根据类型引用获取bean集合
     *
     * @param typeReference 类型引用
     * @return bean对应的集合
     */
    public static <T> Collection<T> getBeansByTypeReference(TypeReference<T> typeReference) {
        ObjectProvider<T> beanProvider = applicationContext.getBeanProvider(ResolvableType.forType(typeReference.getType()));
        return beanProvider.stream().collect(Collectors.toList());
    }

    /**
     * 根据类型获取bean集合
     *
     * @param type 类型
     * @return bean对应的集合
     */
    static <T> Collection<T> getBeansByType(Type type) {
        ObjectProvider<T> beanProvider = applicationContext.getBeanProvider(ResolvableType.forType(type));
        return beanProvider.stream().collect(Collectors.toList());
    }
}
